import traceback
from PyQt5 import QtGui
from PyQt5.QtCore import Qt, QPoint, QTimer
from PyQt5.QtWidgets import QMainWindow, QMessageBox
from PyQt5.QtGui import QColor, QPen, QPainter, QPalette, QBrush, QPixmap, QRadialGradient
from game import Gomoku


def run_with_exc(f):
    # 游戏运行出现错误时，用messagebox把错误信息显示出来

    def call(window, *args, **kwargs):
        try:
            return f(window, *args, **kwargs)
        except Exception:
            exc_info = traceback.format_exc()
            QMessageBox.about(window, '错误信息', exc_info)

    return call


class GomokuWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()  # 初始化游戏界面
        self.g = Gomoku()  # 初始化游戏内容

    def init_ui(self):
        # 初始化棋盘
        self.setObjectName('MainWindow')
        self.setWindowTitle('五子棋')
        self.setFixedSize(640, 640)
        self.setStyleSheet('#MainWindow{background-color: green}')
        self.show()

    @run_with_exc
    def paintEvent(self, e):
        # 绘制游戏内容
        def draw_map():
            # 绘制棋盘
            qp.setPen(QPen(QColor(0, 0, 0), 2, Qt.SolidLine))  # 棋盘的颜色为黑色
            # 绘制横线
            for x in range(15):
                qp.drawLine(40 * (x + 1), 40, 40 * (x + 1), 600)
            # 绘制竖线
            for y in range(15):
                qp.drawLine(40, 40 * (y + 1), 600, 40 * (y + 1))

        def draw_pieces():
            # 绘制棋子
            # 1 绘制黑棋子
            qp.setPen(QPen(QColor(0, 0, 0), 1, Qt.SolidLine))
            qp.setBrush(QColor(0, 0, 0))
            for x in range(15):
                for y in range(15):
                    if self.g.g_map[x][y] == 1:
                        qp.drawEllipse(QPoint(40 * (x + 1), 40 * (y + 1)), 15, 15)
            # 2 绘制白棋子
            qp.setPen(QPen(QColor(255, 255, 255), 1, Qt.SolidLine))
            qp.setBrush(QColor(255, 255, 255))
            for x in range(15):
                for y in range(15):
                    if self.g.g_map[x][y] == 2:
                        qp.drawEllipse(QPoint(40 * (x + 1), 40 * (y + 1)), 15, 15)

        qp = QPainter()
        qp.begin(self)
        draw_map()
        draw_pieces()
        qp.end()

    @run_with_exc
    def mousePressEvent(self, e):
        # 根据鼠标的动作确定落子位置
        if e.button() == Qt.LeftButton:
            # 1 首先判断下在了哪个格子
            mouse_x = e.windowPos().x()
            mouse_y = e.windowPos().y()
            if (mouse_x % 40 <= 15 or mouse_x % 40 >= 25) and (
                    mouse_y % 40 <= 15 or mouse_y % 40 >= 25):
                game_x = int((mouse_x + 15) // 40) - 1
                game_y = int((mouse_y + 15) // 40) - 1
            else:  # 鼠标点击位置不正确
                return
            self.g.move_1step(True, game_x, game_y)
            # 2 根据操作进行一轮游戏循环
            res = self.g.game_result()
            if res != 0:
                self.repaint()
                self.game_restart(res)
                return
            self.g.ai_move_1step()
            res = self.g.game_result()
            if res != 0:
                self.repaint()
                self.game_restart(res)
                return
            self.repaint()

    def game_restart(self, res):
        # 游戏重新开始
        # 1 显示游戏结束的信息
        if res == 1:
            QMessageBox.about(self, '游戏结束', '玩家获胜!')
        elif res == 2:
            QMessageBox.about(self, '游戏结束', 'AI获胜!')
        elif res == 3:
            QMessageBox.about(self, '游戏结束', '平局!')
        else:
            raise ValueError('当前游戏结束的标志位为' + self.res + '. 而游戏结束的标志位必须为1, 2 或 3')
        # 2 游戏重新开始的操作
        self.g = Gomoku()
        self.repaint()
